using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

[System.Serializable]
public class MirrorBlurDoFFeature : ScriptableRendererFeature
{
    [System.Serializable]
    public class Settings
    {
        [Header("When to run")]
        public RenderPassEvent evt = RenderPassEvent.AfterRendering;

        [Tooltip("Only process cameras that render into a target texture (e.g., the mirror reflection camera).")]
        public bool onlyTargetTextureCameras = true;

        [Header("Blur")]
        public bool enableBlur = true;
        [Range(0.1f, 5f)] public float blurRadius = 1.0f;
        [Range(1, 8)] public int iterations = 2;

        [Header("Depth of Field")]
        public bool enableDoF = false;
        [Tooltip("Focus distance in view space (meters)")]
        public float focusDistance = 10f;
        [Tooltip("How quickly blur grows around focus distance")]
        public float focusRange = 5f;
        [Range(0f, 2f)] public float dofIntensity = 1.0f;
    }

    class Pass : ScriptableRenderPass
    {
        static readonly int _MainTex      = Shader.PropertyToID("_MainTex");
        static readonly int _TempA        = Shader.PropertyToID("_MirrorTempA");
        static readonly int _TempB        = Shader.PropertyToID("_MirrorTempB");
        static readonly int _PixelSize    = Shader.PropertyToID("_PixelSize");
        static readonly int _Radius       = Shader.PropertyToID("_Radius");
        static readonly int _FocusDist    = Shader.PropertyToID("_FocusDistance");
        static readonly int _FocusRange   = Shader.PropertyToID("_FocusRange");
        static readonly int _DoFIntensity = Shader.PropertyToID("_DoFIntensity");

        readonly Settings settings;
        readonly Material mat;
        RTHandle cameraColor;

        public Pass(Settings s, Shader shader)
        {
            settings = s;
            mat = CoreUtils.CreateEngineMaterial(shader);
        }

        public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
        {
            cameraColor = renderingData.cameraData.renderer.cameraColorTargetHandle;
            ConfigureInput(settings.enableDoF ? ScriptableRenderPassInput.Depth : ScriptableRenderPassInput.None);
        }

        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
            var cam = renderingData.cameraData.camera;

            // 只处理：目标是 RT 的相机（通常就是 Mirror 反射相机）
            if (settings.onlyTargetTextureCameras && cam.targetTexture == null) return;

            if (!settings.enableBlur && !settings.enableDoF) return;
            if (mat == null) return;

            var cmd = CommandBufferPool.Get("Mirror Blur+DoF");
            var desc = renderingData.cameraData.cameraTargetDescriptor;
            desc.depthBufferBits = 0;

            // 参数
            float pxX = 1.0f / Mathf.Max(1, desc.width);
            float pxY = 1.0f / Mathf.Max(1, desc.height);
            cmd.SetGlobalVector(_PixelSize, new Vector4(pxX, pxY, 0, 0));
            cmd.SetGlobalFloat(_FocusDist, settings.focusDistance);
            cmd.SetGlobalFloat(_FocusRange, Mathf.Max(0.001f, settings.focusRange));
            cmd.SetGlobalFloat(_DoFIntensity, settings.dofIntensity);

            // 临时 RT
            cmd.GetTemporaryRT(_TempA, desc);
            cmd.GetTemporaryRT(_TempB, desc);

            // 第一次把源拷到 A
            Blit(cmd, cameraColor, new RenderTargetIdentifier(_TempA));

            int iters = Mathf.Max(1, settings.iterations);
            float baseRadius = Mathf.Max(0.05f, settings.blurRadius);

            // 多次 Ping-Pong 模糊；如果开了 DoF，半径会按深度自适应
            for (int i = 0; i < iters; i++)
            {
                float r = baseRadius * (i + 1);
                cmd.SetGlobalFloat(_Radius, r);

                // pass 0：水平/对角（Kawase-style）
                CoreUtils.SetKeyword(mat, "_DOF_ON", settings.enableDoF);
                CoreUtils.SetKeyword(mat, "_PASS_ODD", true);
                Blit(cmd, new RenderTargetIdentifier(_TempA), new RenderTargetIdentifier(_TempB), mat, 0);

                // pass 1：垂直/反对角
                CoreUtils.SetKeyword(mat, "_PASS_ODD", false);
                Blit(cmd, new RenderTargetIdentifier(_TempB), new RenderTargetIdentifier(_TempA), mat, 1);
            }

            // 输出回相机目标（= _ReflectionTex）
            Blit(cmd, new RenderTargetIdentifier(_TempA), cameraColor);

            // 回收
            cmd.ReleaseTemporaryRT(_TempA);
            cmd.ReleaseTemporaryRT(_TempB);
            context.ExecuteCommandBuffer(cmd);
            CommandBufferPool.Release(cmd);
        }

        public override void OnCameraCleanup(CommandBuffer cmd) { }
    }

    public Settings settings = new Settings();
    Pass pass;
    Shader shader;

    public override void Create()
    {
        shader = Shader.Find("Hidden/Mirror/BlurDoF");
        pass = new Pass(settings, shader) { renderPassEvent = settings.evt };
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        if (pass == null) Create();
        pass.renderPassEvent = settings.evt;
        renderer.EnqueuePass(pass);
    }
}
